
package com.zui.entity.product;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import com.zui.entity.BaseEntity;
import com.zui.entity.BaseUuidEntity;
import com.zui.entity.party.HabooSupplier;
import com.zui.entity.party.Party;
import com.zui.entity.setup.Uom;
import com.zui.entity.setup.UomType;

@Entity
@org.hibernate.annotations.Entity(
		selectBeforeUpdate = true,dynamicInsert = true, dynamicUpdate=true)
@Table(name="product")
public class Product  extends BaseUuidEntity{
	private static final long serialVersionUID = 1L;
	
	private ProductType productType;
	
	private List<ProductFeatureAppl> productFeatureAppl;
	private List<ProductImage> productImages;

	
		
	/* ----------------------- Wording And Comment ---------------------------- */
	//The Harmonization Id System,<商品名称及编码协调制度>
	private String hsCode;
	private String productCode;
	
	/* ----------------------- for haboo usage only. ---------------------------- */
	private Long price;
	private String unit;
	private String cbm;
	private String weight;
	private HabooSupplier supplier;

	/* ----------------------- Wording And Comment ---------------------------- */
	private String internalName;
	private String brandName;
	private String comments;
	private String longDescription;
	
	private String productName;

	/* ----------------------- Virtual Product ---------------------------- */
	private String isVirtual;
	private String isVariant;
	/**
	 * This field defines the method of selecting a variant from the selectable
	 * features on the virtual product. Either as a variant explosion which will
	 * work to about 200 variants or as feature explosion which almost has no
	 * limits
	 */
	private String virtualVariantMethodEnum;
	
	/* ----------------------- Primary Category ---------------------------- */
	/**
	 * The primary category ; it should be one of the productCategoryId already
	 * setup in ProductCategoryMember
	 */
	private Category primaryCategory;
	public void setPrimaryCategory(Category primaryCategory) {
		this.primaryCategory = primaryCategory;
		this.addProductCategory(primaryCategory, BaseEntity.FLAG_Y);
	}
	private List<ProductCategory> productCategories;
	
	/* ----------------------- Dates ---------------------------- */
	private Date introductionDate;
	private Date releaseDate;
	private Date salesDiscontinuationDate;
	private Date supportDiscontinuationDate;
	
	/* ----------------------- rating ---------------------------- */
	private Long productRating;
	private String ratingTypeEnum;	
	
	/* ----------------------- Amount ---------------------------- */
	private String requireAmount;
	private UomType amountUomType;
	/**
	 * Use this for products which are sold in fixed denominations, such as gift
	 * certificates or calling cards.
	 */
	private Long fixedAmount;
	
	/* ----------------------- Measures ---------------------------- */
	private Uom heightUom;
	private Long productHeight;
	private Long shippingHeight;
	private Uom widthUom;
	private Long productWidth;
	private Long shippingWidth;
	private Uom depthUom;
	private Long productDepth;
	private Long shippingDepth;
	private Uom diameterUom;
	private Long productDiameter;
	private Uom weightUom;
	private Long shippingWeight;
	private Long productWeight;
	private Uom quantityUom;
	private Long quantityIncluded;
	
	/* ----------------------- shipping ---------------------------- */
	private Long piecesIncluded;
	private String inShippingBox;
	private ShipmentBoxType defaultShipmentBoxType;
	private String chargeShipping;
	
	/* ----------------------- Miscellaneous ---------------------------- */
	private String returnable;
	private String includeInPromotions;
	private String taxable;
	private String autoCreateKeywords;

	/* ----------------------- Geos ---------------------------- */
	
	private Geo originGeo;
	
	/* ----------------------- unknow ---------------------------- */
	
	private String priceDetailText;
	private String smallImageUrl;
	private String mediumImageUrl;
	private String largeImageUrl;
	private String detailImageUrl;
	private String originalImageUrl;
	private String detailScreen;
	private String inventoryMessage;
	private String requireInventory;
	private String requirementMethodEnumId;
	private Integer billOfMaterialLevel;
	/**
	 * maximum number of persons who can rent this asset at the same time
	 */
	private Long reservMaxPersons;
	/**
	 * percentage of the end price for the 2nd person renting this asset
	 * connected to this product
	 */
	private Long reserv2ndPPPerc;
	/**
	 * percentage of the end price for the Nth person renting this asset
	 * connected to this product
	 */
	private Long reservNthPPPerc;
	/**
	 * Used to safe the persisted configuration Id for AGGREGATED products.
	 */
	private String configId;

	private Party manufactureParty;
	private Facility facility;

	//*********** utility methods *****************************
	@Transient
	public String getPrimaryListViewImageUrl(){
		if (productImages ==null || productImages.isEmpty())
			return "";
		String url = null;
		for (ProductImage pi:productImages) {
			if (BaseEntity.FLAG_Y.equals(pi.getPrimaryFlag())){
				url = pi.getImage().getListViewImageUrl();
				break;
			}
		}
		return url==null?productImages.get(0).getImage().getListViewImageUrl():url;
	}
	@Transient
	public String getPrimaryThumbViewImageUrl(){
		if (productImages ==null || productImages.isEmpty())
			return "";
		String url = null;
		for (ProductImage pi:productImages) {
			if (BaseEntity.FLAG_Y.equals(pi.getPrimaryFlag())){
				url = pi.getImage().getThumbViewImageUrl();
				break;
			}
		}
		return url==null?productImages.get(0).getImage().getThumbViewImageUrl():url;
	}
	@Transient
	public String getPrimarySmallImageUrl(){
		if (productImages ==null || productImages.isEmpty())
			return "";
		String url = null;
		for (ProductImage pi:productImages) {
			if (BaseEntity.FLAG_Y.equals(pi.getPrimaryFlag())){
				url = pi.getImage().getSmallImageUrl();
				break;
			}
		}
		return url==null?productImages.get(0).getImage().getSmallImageUrl():url;
	}
	@Transient
	public String getPrimaryMediumImageUrl(){
		if (productImages ==null || productImages.isEmpty())
			return "";
		String url = null;
		for (ProductImage pi:productImages) {
			if (BaseEntity.FLAG_Y.equals(pi.getPrimaryFlag())){
				url = pi.getImage().getMediumImageUrl();
				break;
			}
		}
		return url==null?productImages.get(0).getImage().getMediumImageUrl():url;
	}
	@Transient
	public String getPrimaryOriginalImageUrl(){
		if (productImages ==null || productImages.isEmpty())
			return "";
		String url = null;
		for (ProductImage pi:productImages) {
			if (BaseEntity.FLAG_Y.equals(pi.getPrimaryFlag())){
				url = pi.getImage().getOriginalImageUrl();
				break;
			}
		}
		return url==null?productImages.get(0).getImage().getOriginalImageUrl():url;
	}
	@Transient
	public void addProductCategory(Category cat, String primaryFlag) {
		ProductCategory pc = new ProductCategory();
		pc.setPrimaryFlag(primaryFlag);
		pc.setCategory(cat);
		pc.setProduct(this);
		if(productCategories == null)
			productCategories = new ArrayList<ProductCategory>();
		productCategories.add(pc);
	}
	@Transient
	public void addProductCategory(ProductCategory pc) {
		pc.setProduct(this);
		if(productCategories == null)
			productCategories = new ArrayList<ProductCategory>();
		productCategories.add(pc);
	}
	@Transient
	public void removeProductCategory(ProductCategory pc) {
		if(productCategories == null)
			return;
		//update primaryCategory
		if(FLAG_Y.equals(pc.getPrimaryFlag()))
			primaryCategory = null;
		this.getProductFeatureAppl().remove(pc);
		pc.setProduct(null);
	}	
	@Transient
	public void addProductFeatureAppl(Feature feature) {
		ProductFeatureAppl pfa = new ProductFeatureAppl();
		pfa.setFeature(feature);
		pfa.setProduct(this);
		if(productFeatureAppl == null)
			productFeatureAppl = new ArrayList<ProductFeatureAppl>();
		productFeatureAppl.add(pfa);
	}
	@Transient
	public void addProductFeatureAppl(ProductFeatureAppl pfa) {
		pfa.setProduct(this);
		if(productFeatureAppl == null)
			productFeatureAppl = new ArrayList<ProductFeatureAppl>();
		productFeatureAppl.add(pfa);
	}
	@Transient
	public void removeProductFeatureAppl(ProductFeatureAppl pfa) {
		if(productFeatureAppl == null)
			return;
		this.getProductFeatureAppl().remove(pfa);
		pfa.setProduct(null);
	}
	@Transient
	public void addProductImage(Image image) {
		ProductImage pi = new ProductImage();
		pi.setImage(image);
		pi.setProduct(this);
		if(productImages == null) {
			productImages = new ArrayList<ProductImage>();
			pi.setSequenceNum(1);
		} else
			pi.setSequenceNum(productImages.size());
		productImages.add(pi);
	}
	@Transient
	public void addProductImage(ProductImage pi) {
		pi.setProduct(this);
		if(productImages == null) {
			productImages = new ArrayList<ProductImage>();
			pi.setSequenceNum(1);
		} else
			pi.setSequenceNum(productImages.size());
		productImages.add(pi);
	}
	@Transient
	public void removeProductImage(ProductImage pi) {
		if(productImages == null)
			return;
		this.getProductImages().remove(pi);
		pi.setProduct(null);
	}
	
	//*********** getter *****************************
	@ManyToOne
	@JoinColumn(name="primaryCategoryId")	
	public Category getPrimaryCategory() {return primaryCategory;}
	
	@OneToMany(mappedBy="product", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
	@OrderBy(value="sequenceNum")
	public List<ProductFeatureAppl> getProductFeatureAppl() { return productFeatureAppl; }

	@OneToMany(mappedBy="product", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
	@OrderBy(value="sequenceNum")
	public List<ProductImage> getProductImages() { return productImages; }
	
	@Column(length=20)
	public String getHsCode() {return hsCode;}
	@Column(length=20,unique=true)
	public String getProductCode() {return productCode;}
	public Long getPrice() {return price;}
	@ManyToOne
	@JoinColumn(name="productTypeId")
	public ProductType getProductType() {return productType;}

	@OneToMany(mappedBy = "product", fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
	@OrderBy(value = "sequenceNum")
	public List<ProductCategory> getProductCategories() {
		return productCategories;
	}
	@ManyToOne
	@JoinColumn(name="manufacturePartyId")	
	public Party getManufactureParty() {return manufactureParty;}
	@ManyToOne
	@JoinColumn(name="facilityId")
	public Facility getFacility() {return facility;}
	@Temporal(TemporalType.DATE)
	public Date getIntroductionDate() {return introductionDate;}
	@Temporal(TemporalType.DATE)
	public Date getReleaseDate() {return releaseDate;}
	@Temporal(TemporalType.TIME)
	public Date getSalesDiscontinuationDate() {return salesDiscontinuationDate;}
	@Temporal(TemporalType.TIME)
	public Date getSupportDiscontinuationDate() {return supportDiscontinuationDate;}
	@Column(length=50)
	public String getInternalName() {return internalName;}
	@Column(length=50)
	public String getBrandName() {return brandName;}
	@Column(length=256)
	public String getComments() {return comments;}
	@Column(length=50)
	public String getProductName() {return productName;}
	@Lob
	public String getLongDescription() {return longDescription;}
	public String getPriceDetailText() {return priceDetailText;}
	@Column(length=256)
	public String getSmallImageUrl() {return smallImageUrl;}
	@Column(length=256)
	public String getMediumImageUrl() {return mediumImageUrl;}
	@Column(length=100)
	public String getLargeImageUrl() {return largeImageUrl;}
	@Column(length=100)
	public String getDetailImageUrl() {return detailImageUrl;}
	@Column(length=100)
	public String getOriginalImageUrl() {return originalImageUrl;}
	@Column(length=100)
	public String getDetailScreen() {return detailScreen;}
	@Column(length=100)
	public String getInventoryMessage() {return inventoryMessage;}
	public String getRequireInventory() {return requireInventory;}
	@ManyToOne
	@JoinColumn(name="quantityUomId")
	public Uom getQuantityUom() {return quantityUom;}
	public Long getQuantityIncluded() {
		return quantityIncluded;
	}
	public Long getPiecesIncluded() {
		return piecesIncluded;
	}
	public String getRequireAmount() {
		return requireAmount;
	}
	public Long getFixedAmount() {
		return fixedAmount;
	}
	@ManyToOne
	@JoinColumn(name="amountUomTypeId")
	public UomType getAmountUomType() {
		return amountUomType;
	}
	@ManyToOne
	@JoinColumn(name="weightUomId")
	public Uom getWeightUom() {return weightUom;}
	public Long getShippingWeight() {return shippingWeight;}
	public Long getProductWeight() {
		return productWeight;
	}
	@ManyToOne
	@JoinColumn(name="heightUomId")
	public Uom getHeightUom() {return heightUom;}
	public Long getProductHeight() {return productHeight;}
	public Long getShippingHeight() {return shippingHeight;}
	@ManyToOne
	@JoinColumn(name="widthUomId")
	public Uom getWidthUom() {return widthUom;}
	public Long getProductWidth() {return productWidth;}
	public Long getShippingWidth() {return shippingWidth;}
	@ManyToOne
	@JoinColumn(name="depthUomId")
	public Uom getDepthUom() {return depthUom;}
	public Long getProductDepth() {return productDepth;}
	public Long getShippingDepth() {return shippingDepth;}
	@ManyToOne
	@JoinColumn(name="diameterUomId")
	public Uom getDiameterUom() {return diameterUom;}
	public Long getProductDiameter() {return productDiameter;}
	public Long getProductRating() {return productRating;}
	public String getRatingTypeEnum() {return ratingTypeEnum;}
	@Column(length=1)
	public String getReturnable() {return returnable;}
	@Column(length=1)
	public String getTaxable() {return taxable;}
	@Column(length=1)
	public String getChargeShipping() {return chargeShipping;}
	@Column(length=1)
	public String getAutoCreateKeywords() {return autoCreateKeywords;}
	@Column(length=1)
	public String getIncludeInPromotions() {return includeInPromotions;}
	@Column(length=1)
	public String getIsVirtual() {return isVirtual;}
	@Column(length=1)
	public String getIsVariant() {return isVariant;}
	public String getVirtualVariantMethodEnum() {
		return virtualVariantMethodEnum;
	}
	@ManyToOne
	@JoinColumn(name="originGeoId")
	public Geo getOriginGeo() {return originGeo;}
	public String getRequirementMethodEnumId() {
		return requirementMethodEnumId;
	}
	public Integer getBillOfMaterialLevel() {
		return billOfMaterialLevel;
	}
	public Long getReservMaxPersons() {
		return reservMaxPersons;
	}
	public Long getReserv2ndPPPerc() {
		return reserv2ndPPPerc;
	}
	public Long getReservNthPPPerc() {
		return reservNthPPPerc;
	}
	public String getConfigId() {
		return configId;
	}
	public String getInShippingBox() {
		return inShippingBox;
	}
	public ShipmentBoxType getDefaultShipmentBoxType() {
		return defaultShipmentBoxType;
	}
	@ManyToOne
	@JoinColumn(name="habooSupplierId")
	public HabooSupplier getSupplier() {
		return supplier;
	}
	
	//*********** getter and setter*******************


	public void setProductType(ProductType productType) {
		this.productType = productType;
	}
	public void setProductCategories(
			List<ProductCategory> productCategories) {
		this.productCategories = productCategories;
	}
	public void setProductFeatureAppl(List<ProductFeatureAppl> productFeatureAppl) {
		this.productFeatureAppl = productFeatureAppl;
	}
	public void setManufactureParty(Party manufactureParty) {
		this.manufactureParty = manufactureParty;
	}
	public void setFacility(Facility facility) {
		this.facility = facility;
	}
	public void setIntroductionDate(Date introductionDate) {
		this.introductionDate = introductionDate;
	}
	public void setReleaseDate(Date releaseDate) {
		this.releaseDate = releaseDate;
	}
	public void setSalesDiscontinuationDate(Date salesDiscontinuationDate) {
		this.salesDiscontinuationDate = salesDiscontinuationDate;
	}
	public void setSupportDiscontinuationDate(Date supportDiscontinuationDate) {
		this.supportDiscontinuationDate = supportDiscontinuationDate;
	}
	public void setInternalName(String internalName) {
		this.internalName = internalName;
	}
	public void setBrandName(String brandName) {
		this.brandName = brandName;
	}
	public void setComments(String comments) {
		this.comments = comments;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public void setLongDescription(String longDescription) {
		this.longDescription = longDescription;
	}
	public void setPriceDetailText(String priceDetailText) {
		this.priceDetailText = priceDetailText;
	}
	public void setSmallImageUrl(String smallImageUrl) {
		this.smallImageUrl = smallImageUrl;
	}
	public void setMediumImageUrl(String mediumImageUrl) {
		this.mediumImageUrl = mediumImageUrl;
	}
	public void setLargeImageUrl(String largeImageUrl) {
		this.largeImageUrl = largeImageUrl;
	}
	public void setDetailImageUrl(String detailImageUrl) {
		this.detailImageUrl = detailImageUrl;
	}
	public void setOriginalImageUrl(String originalImageUrl) {
		this.originalImageUrl = originalImageUrl;
	}
	public void setDetailScreen(String detailScreen) {
		this.detailScreen = detailScreen;
	}
	public void setInventoryMessage(String inventoryMessage) {
		this.inventoryMessage = inventoryMessage;
	}
	public void setRequireInventory(String requireInventory) {
		this.requireInventory = requireInventory;
	}
	public void setQuantityUom(Uom quantityUom) {
		this.quantityUom = quantityUom;
	}
	public void setQuantityIncluded(Long quantityIncluded) {
		this.quantityIncluded = quantityIncluded;
	}
	public void setPiecesIncluded(Long piecesIncluded) {
		this.piecesIncluded = piecesIncluded;
	}
	public void setRequireAmount(String requireAmount) {
		this.requireAmount = requireAmount;
	}
	public void setFixedAmount(Long fixedAmount) {
		this.fixedAmount = fixedAmount;
	}
	public void setAmountUomType(UomType amountUomType) {
		this.amountUomType = amountUomType;
	}
	public void setWeightUom(Uom weightUom) {
		this.weightUom = weightUom;
	}
	public void setShippingWeight(Long shippingWeight) {
		this.shippingWeight = shippingWeight;
	}
	public void setProductWeight(Long productWeight) {
		this.productWeight = productWeight;
	}
	public void setHeightUom(Uom heightUom) {
		this.heightUom = heightUom;
	}
	public void setProductHeight(Long productHeight) {
		this.productHeight = productHeight;
	}
	public void setShippingHeight(Long shippingHeight) {
		this.shippingHeight = shippingHeight;
	}
	public void setWidthUom(Uom widthUom) {
		this.widthUom = widthUom;
	}
	public void setProductWidth(Long productWidth) {
		this.productWidth = productWidth;
	}
	public void setShippingWidth(Long shippingWidth) {
		this.shippingWidth = shippingWidth;
	}
	public void setDepthUom(Uom depthUom) {
		this.depthUom = depthUom;
	}
	public void setProductDepth(Long productDepth) {
		this.productDepth = productDepth;
	}
	public void setShippingDepth(Long shippingDepth) {
		this.shippingDepth = shippingDepth;
	}
	public void setDiameterUom(Uom diameterUom) {
		this.diameterUom = diameterUom;
	}
	public void setProductDiameter(Long productDiameter) {
		this.productDiameter = productDiameter;
	}
	public void setProductRating(Long productRating) {
		this.productRating = productRating;
	}
	public void setRatingTypeEnum(String ratingTypeEnum) {
		this.ratingTypeEnum = ratingTypeEnum;
	}
	public void setReturnable(String returnable) {
		this.returnable = returnable;
	}
	public void setTaxable(String taxable) {
		this.taxable = taxable;
	}
	public void setChargeShipping(String chargeShipping) {
		this.chargeShipping = chargeShipping;
	}
	public void setAutoCreateKeywords(String autoCreateKeywords) {
		this.autoCreateKeywords = autoCreateKeywords;
	}
	public void setIncludeInPromotions(String includeInPromotions) {
		this.includeInPromotions = includeInPromotions;
	}
	public void setIsVirtual(String isVirtual) {
		this.isVirtual = isVirtual;
	}
	public void setIsVariant(String isVariant) {
		this.isVariant = isVariant;
	}
	public void setVirtualVariantMethodEnum(String virtualVariantMethodEnum) {
		this.virtualVariantMethodEnum = virtualVariantMethodEnum;
	}
	public void setOriginGeo(Geo originGeo) {
		this.originGeo = originGeo;
	}
	public void setRequirementMethodEnumId(String requirementMethodEnumId) {
		this.requirementMethodEnumId = requirementMethodEnumId;
	}
	public void setBillOfMaterialLevel(Integer billOfMaterialLevel) {
		this.billOfMaterialLevel = billOfMaterialLevel;
	}
	public void setReservMaxPersons(Long reservMaxPersons) {
		this.reservMaxPersons = reservMaxPersons;
	}
	public void setReserv2ndPPPerc(Long reserv2ndPPPerc) {
		this.reserv2ndPPPerc = reserv2ndPPPerc;
	}
	public void setReservNthPPPerc(Long reservNthPPPerc) {
		this.reservNthPPPerc = reservNthPPPerc;
	}
	public void setConfigId(String configId) {
		this.configId = configId;
	}
	public void setInShippingBox(String inShippingBox) {
		this.inShippingBox = inShippingBox;
	}
	public void setDefaultShipmentBoxType(ShipmentBoxType defaultShipmentBoxType) {
		this.defaultShipmentBoxType = defaultShipmentBoxType;
	}
	public void setProductCode(String productCode) {
		this.productCode = productCode;
	}
	public void setPrice(Long price) {
		this.price = price;
	}
	public void setHsCode(String hsCode) {
		this.hsCode = hsCode;
	}
	public void setProductImages(List<ProductImage> productImages) {
		this.productImages = productImages;
	}
	public String getUnit() {
		return unit;
	}
	public String getCbm() {
		return cbm;
	}
	public String getWeight() {
		return weight;
	}
	public void setUnit(String unit) {
		this.unit = unit;
	}
	public void setCbm(String cbm) {
		this.cbm = cbm;
	}
	public void setWeight(String weight) {
		this.weight = weight;
	}
	public void setSupplier(HabooSupplier supplier) {
		this.supplier = supplier;
	}
	
}
